#include "draw.h"
#include "render.h"

#ifdef DRAW_OPENGL_2
int g_QuadDL[6];
int g_2DQuadDL;
#endif

#ifdef DRAW_OPENGL_3
CViewMatrix viewMatrix;
GLuint GL3VertexBuffer;

GLuint GL3ElementBuffer;
#endif

CShaderSystem * pShaderSystem;
GLuint blankPixel;
GLuint posAttrib;
GLuint colorUniform;
GLuint translateUniform;
GLuint scaleUniform;
GLuint STmulUniform;
GLuint ST1offsetUniform;
GLuint ST2offsetUniform;

bool bCull;

void Draw::SetBlankPixel( GLuint i )
{
	
	blankPixel = i;
	
}

void Draw::DisableTextures()
{
	
	Draw::BindTexture( blankPixel );
	
}

void Draw::EnableTextures()
{
	
	Draw::BindTexture( 0 );
	
}

void Draw::SetShaderProgram( int i )
{
	
	pShaderSystem->SetProgram( i );
	
}

void Draw::SetShaderSystem( CShaderSystem * sys, int prog )
{

	pShaderSystem = sys;
	
	posAttrib = pShaderSystem->GetAttribLocation( prog, "position" );
	translateUniform = pShaderSystem->GetUniformLocation( prog, "translate" );
	scaleUniform = pShaderSystem->GetUniformLocation( prog, "scale" );
	colorUniform = pShaderSystem->GetUniformLocation( prog, "color" );
	STmulUniform = pShaderSystem->GetUniformLocation( prog, "stmul" );
	ST1offsetUniform = pShaderSystem->GetUniformLocation( prog, "st1offset" );
	ST2offsetUniform = pShaderSystem->GetUniformLocation( prog, "st2offset" );
	
}

void Draw::InitShaderValues( int prog )
{
	
	
	Draw::SetShaderProgram( prog );
	Draw::SetSTOffsets( 0, 0, 1, 1 );
	Draw::Color4f( 1.0f, 1.0f, 1.0f, 1.0f );
	Draw::SetSTMul( 1.0f, 1.0f );
	
	bCull = false;
	
}

 void Draw::SetCull( bool b )
{
	
	bCull = b;
	
}

void Draw::Push()
{
	
#if defined( DRAW_OPENGL_2 )
	glPushMatrix();
#elif defined( DRAW_OPENGL_3 )
	viewMatrix.Push();
#endif
	
}


void Draw::Pop()
{
	
#if defined( DRAW_OPENGL_2 )
	glPopMatrix();
#elif defined( DRAW_OPENGL_3 )
	viewMatrix.Pop();
#endif
	
}

void Draw::Translate( float x, float y, float z )
{
	
#ifdef DRAW_OPENGL_3
	viewMatrix.Translate( x, y, z );
#elif defined( DRAW_OPENGL_2 )
	glTranslatef( x, y, z );
#endif
	
}
	
void Draw::Scale( float x, float y, float z )
{
	
#ifdef DRAW_OPENGL_3
	viewMatrix.Scale( x, y, z );
#elif defined( DRAW_OPENGL_2 )
	glScalef( x, y, z );
#endif
	
}

void Draw::VertexBuffer()
{
	
#ifdef DRAW_OPENGL_3

	if( bCull )
		if( !viewMatrix.CurQuadInScreen() )
			return;

	viewMatrix.BindToGLSLUniform( translateUniform, scaleUniform );

	glDrawElements( GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, ( void * )0 );

#endif
	
}

void Draw::GetMatrix( float * matrix )
{
	
#ifdef DRAW_OPENGL_2
	glGetFloatv( GL_MODELVIEW_MATRIX, matrix );
#endif
	
}

float * Draw::GetTranslate()
{

#ifdef DRAW_OPENGL_3
	return viewMatrix.GetTranslate();
#endif
	
}

void Draw::UnbindVertexAttribPointer()
{
	
#ifdef DRAW_OPENGL_3

	glDisableVertexAttribArray( posAttrib );

#endif
	
}

void Draw::BindVertexAttribPointer()
{
	
#ifdef DRAW_OPENGL_3 

	glBindBuffer( GL_ARRAY_BUFFER, GL3VertexBuffer );
	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GL3ElementBuffer );

	glEnableVertexAttribArray( posAttrib );
	glVertexAttribPointer( posAttrib, 2, GL_FLOAT, GL_FALSE, 0, ( void * )0 );


#endif
	
}

void Draw::BindTexture( GLuint tex )
{
		
#if defined( DRAW_OPENGL_2 ) || defined( DRAW_OPENGL_3 )

	glBindTexture( GL_TEXTURE_2D, tex );

#endif
	
}

void Draw::LoadIdentity()
{
	
#ifdef DRAW_OPENGL_3 

	viewMatrix.LoadIdentity();

#elif defined( DRAW_OPENGL_2 )

	glLoadIdentity();
	
#endif
	
}

void Draw::SetSTOffsets( float x1, float y1, float x2, float y2 )
{
	
	float v1[] = { x1, y1 };
	float v2[] = { x2, y2 };
	
	glUniform2fv( ST1offsetUniform, 1, v1 );
	glUniform2fv( ST2offsetUniform, 1, v2 );
	
}

void Draw::SetSTMul( float x, float y )
{
	
	float v[] = { x, y };
	
	glUniform2fv( STmulUniform, 1, v );
	
}

void Draw::InitOpenGL3Context()
{
	
#ifdef DRAW_OPENGL_3
	
	GLfloat vertex_buffer_data[] = {
		
		0.0f, 0.0f,
		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f
		
	};
	
	GLushort element_buffer_data[] = {
		
		3, 0, 1, 3, 2, 1
		
	};
	
	glGenBuffers( 1, &GL3VertexBuffer );
	glBindBuffer( GL_ARRAY_BUFFER, GL3VertexBuffer );
	glBufferData( GL_ARRAY_BUFFER, sizeof( vertex_buffer_data ), vertex_buffer_data, GL_STATIC_DRAW );
	
	glGenBuffers( 1, &GL3ElementBuffer );
	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GL3ElementBuffer );
	glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( element_buffer_data ), element_buffer_data, GL_STATIC_DRAW );

#endif
	
}

void Draw::FreeOpenGL3Context()
{
	
#ifdef DRAW_OPENGL_3

	glDeleteBuffers( 1, &GL3VertexBuffer );
	glDeleteBuffers( 1, &GL3ElementBuffer );

#endif
	
}

void InitQuadDL()
{
	
#ifdef DRAW_OPENGL_2
	float x[] = 
	{
		
		0.0f, 0.0f, 1.0f,
		1.0f, 0.0f, 1.0f,
		
	};
	
	float y[] =
	{
		
		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 1.0f,
		
	};
	
	for( int j = 0; j < 6; j++ )
	{
	
		g_QuadDL[j] = glGenLists( 1 );
	
		glNewList( g_QuadDL[j], GL_COMPILE );
	
			glTexCoord2f( x[j], y[j] );
			glVertex3f( x[j], y[j], 0.0f );
	
		glEndList();
		
	}
	
	g_2DQuadDL = glGenLists( 1 );
	
	glNewList( g_2DQuadDL, GL_COMPILE );

		glBegin( GL_TRIANGLE_STRIP );
		
		for( int j = 0; j < 6; j++ )
		{
			
			glTexCoord2f( x[j], y[j] );
			glVertex2f( x[j], y[j] );
			
		}
		
		glEnd();
		
	glEndList();
	
#endif
	
}

void Draw::InitDrawLists()
{
	
#ifdef DRAW_OPENGL_2

	InitQuadDL();

#endif
	
}

void Draw::FreeDrawLists()
{

#ifdef DRAW_OPENGL_2
	
	for( int j = 0; j < 6; j++ )
	{
	
		glDeleteLists( g_QuadDL[j], 1 );
		
	}
	
	glDeleteLists( g_2DQuadDL, 1 );
	
#endif
	
}

void Draw::RawQuad()
{
	
#ifdef DRAW_OPENGL_2
	glCallList( g_2DQuadDL );
#elif defined( DRAW_OPENGL_3 )
	Draw::VertexBuffer();
#endif
	
}

void Draw::Color4f( float r, float g, float b, float a )
{
	
#ifdef DRAW_OPENGL_2
	glColor4f( r, g, b, a );
#elif defined( DRAW_OPENGL_3 )
	float rgba[] = { r, g, b, a };
	glUniform4fv( colorUniform, 1, rgba );
#endif
	
}

void Draw::Quad( double x, double y, double z, int w, int h )
{

	PUSH_MATRIX;
	
		Draw::Translate( x, y, z );
		Draw::Scale( w, h, 1.0f );
		
		Draw::RawQuad();
		
	POP_MATRIX;
	
}


void Draw::TexturedQuad( double x, double y, int w, int h )
{

	PUSH_MATRIX;
	
	Draw::Translate( x, y, 0.0f );
	Draw::Scale( w, h, 1 );
	
	Draw::RawQuad();
	
	POP_MATRIX;

}

void Draw::TexturedQuad( Vector2D pos, int w, int h )
{

	TexturedQuad( pos.x, pos.y, w, h );

}